﻿/*   
    Copyright (C) 2009 Galaktika Corporation ZAO

    This file is a part of Galaktika.BusinessMonitor
 
    Galaktika.BusinessMonitor is a free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
      
    You should have received a copy of the GNU General Public License
    along with Galaktika.BusinessMonitor.  If not, see <http://www.gnu.org/licenses/>.
  
    If GPL v.3 is not suitable for your products or company,
    Galaktika Corp provides Galaktika.BusinessMonitor under a flexible commercial license
    designed to meet your specific usage and distribution requirements.
    If you have already obtained a commercial license from Galaktika Corp,
    you can use this file under those license terms.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Galaktika.BI.Charting;
using Galaktika.BI.Extensibility.Dom;
using Galaktika.BI.Runtime.Services;
using Galaktika.BI.Silverlight.Runtime.Data.Olap;
using Ranet.Olap.Core.Data;
using Galaktika.BI.Silverlight.Runtime.Data;
using Galaktika.BI.Silverlight.Services;
using System.Text;
using Galaktika.BI.Extensibility;

namespace Galaktika.BI.Silverlight.Controls
{
    public class Selector : ComboBox, IBindableObject, IEditableObject
    {
        private bool m_FirstLoad = true;
        private ComboBox cbox;
        //private ScrollViewer scrollViewer;
        private Popup elementPopup;
        private FrameworkElement elementPopupChild;

        public Selector()
        {
            //InitializeComponent();
            cbox = this;
            cbox.SelectionChanged += new SelectionChangedEventHandler(cbox_SelectedIndexChanged);
            //cbox.DropDownOpened += new EventHandler(cbox_DropDownOpened);
            this.IsEnabled = false;
            this.IsMouseWheelAttached = false;
            base.DefaultStyleKey = typeof(Selector);
        }

        void cbox_DropDownOpened(object sender, EventArgs e)
        {
            this.elementPopup = this.GetPopup();
            this.elementPopupChild = this.elementPopup.Child as Canvas;
            this.GotFocus += new RoutedEventHandler(elementPopupChild_GotFocus);
            //this.LostFocus += new RoutedEventHandler(elementPopup_LostFocus);
            //this.elementPopupChild.MouseEnter += new MouseEventHandler(elementPopup_MouseEnter);
            //this.elementPopupChild.MouseLeave += new MouseEventHandler(elementPopup_MouseLeave);
        }

        //void elementPopup_LostFocus(object sender, RoutedEventArgs e)
        //{
        //    this.IsMouseWheelAttached = false;
        //    this.RemoveMouseWheelSupport();
        //}

        void elementPopupChild_GotFocus(object sender, RoutedEventArgs e)
        {
            if (!this.IsMouseWheelAttached)
            {
                this.AddMouseWheelSupport();
            } 
        }

        //void elementPopup_MouseLeave(object sender, MouseEventArgs e)
        //{
        //    this.IsMouseWheelAttached = false;
        //}

        //void elementPopup_MouseEnter(object sender, MouseEventArgs e)
        //{
        //    if (!this.IsMouseWheelAttached)
        //    {
        //        this.AddMouseWheelSupport();
        //    } 
        //}

        private object m_DataSource;
        [Browsable(false)]
        public object ADataSource
        {
            get
            {
                return m_DataSource;
            }
            set
            {
                m_DataSource = value;
            }
        }

        private string m_Variable = string.Empty;
        [Browsable(false)]
        public string AVariable
        {
            get { return m_Variable; }
            set
            {
                m_Variable = value;
            }
        }

        private string m_Path = string.Empty;
        [Browsable(false)]
        public string APath
        {
            get { return m_Path; }
            set { m_Path = value; }
        }

        private string m_NameItem = string.Empty;
        [Browsable(false)]
        public string ANameItem
        {
            get { return m_NameItem; }
            set { m_NameItem = value; }
        }

        private string m_ValueItem = string.Empty;
        [Browsable(false)]
        public string AValueItem
        {
            get { return m_ValueItem; }
            set { m_ValueItem = value; }
        }

        public bool IsMouseWheelAttached { get; set; }

        public Popup GetPopup()
        {
           return base.GetTemplateChild("Popup") as Popup;
        }

        public ScrollViewer GetScroller()
        {
            //if (base.GetTemplateChild("ScrollViewer") as ScrollViewer != null)
             return base.GetTemplateChild("ScrollViewer") as ScrollViewer;
        }

        #region IBindableObject Members

        private IBindingContext m_Context;
        public IBindingContext Context
        {
            get
            {
                return m_Context;
            }
            set
            {
                m_Context = value;
            }
        }

        private Dictionary<string, IBindingManager> m_Bindings;
        public IDictionary<string, IBindingManager> Bindings
        {
            get
            {
                if (m_Bindings == null)
                {
                    m_Bindings = new Dictionary<string, IBindingManager>();
                }

                return m_Bindings;
            }
        }

        #endregion

        private void PopulateItems(BrickVariable var)
        {
            cbox.Items.Clear();
            if (var != null)
            {
                // TODO: navigate using Path
                // TODO: consume JsonObject too

                var jsonArray = Jayrock.Json.Conversion.JsonConvert.Import(var.Value) as Jayrock.Json.JsonArray;
                if (jsonArray != null)
                {
                    foreach (var o in jsonArray)
                    {
                        var jsonObj = o as Jayrock.Json.JsonObject;
                        if (jsonObj == null) continue;

                        if (jsonObj.Contains(m_NameItem) && jsonObj.Contains(m_ValueItem))
                        {

                            SelectorItem item = new SelectorItem()
                            {
                                Content = jsonObj[m_NameItem].ToString(),
                                Tag = jsonObj[m_ValueItem].ToString()
                            };
                            cbox.Items.Add(item);
                        }
                        else
                        {
                            var output = (IOutputService)this.Context.Services.GetService(typeof(IOutputService));
                            if (output != null)
                            {
                                StringBuilder sb = new StringBuilder();
                                foreach (System.Collections.DictionaryEntry item in jsonObj)
                                {
                                    if (sb.Length != 0)
                                    {
                                        sb.Append(", ");
                                    }
                                    sb.Append(item);
                                }

                                if (sb.Length == 0)
                                {
                                    sb.Append(Localization.Str_None);
                                }

                                output.WriteLine(string.Format(Localization.Selector_InvalidNameValueItem,
                                    base.Name,
                                    m_NameItem,
                                    m_ValueItem,
                                    sb));
                            }
                            break;
                        }

                    }
                }
            }

            /*
                using (JsonParser parser = new JsonParser(new StringReader(var.Value), true))
                {
                    JsonArray array = parser.ParseArray();
                    for (int i = 0; i < array.Count; i++)
                    {
                        JsonObject obj = (JsonObject)array[i];
                        if (obj.ContainsKey(m_NameItem) && obj.ContainsKey(m_ValueItem))
                        {

                            SelectorItem item = new SelectorItem()
                            {
                                Content = obj[m_NameItem].ToString(),
                                Tag = obj[m_ValueItem].ToString()
                            };
                            cbox.Items.Add(item);
                        }
                        else
                        {
                            IOutputService output = (IOutputService)this.Context.Services.GetService(typeof(IOutputService));
                            if (output != null)
                            {
                                StringBuilder sb = new StringBuilder();
                                foreach (var item in obj.Keys)
                                {
                                    if (sb.Length != 0)
                                    {
                                        sb.Append(", ");
                                    }
                                    sb.Append(item);
                                }

                                if (sb.Length == 0)
                                {
                                    sb.Append(Localization.Str_None);
                                }

                                output.WriteLine(string.Format(Localization.Selector_InvalidNameValueItem,
                                    base.Name,
                                    m_NameItem,
                                    m_ValueItem,
                                    sb));
                            }
                            break;
                        }
                    }
                }
             */
        }

        private void SetDefaultValue(BrickVariable var)
        {
            if (var != null)
            {
                var jsonArray = Jayrock.Json.Conversion.JsonConvert.Import(var.Value) as Jayrock.Json.JsonArray;
                if (jsonArray != null)
                {
                    for (int i = 0; i < jsonArray.Length; i++)
                    {
                        var jsonObj = jsonArray[i] as Jayrock.Json.JsonObject;
                        if (jsonObj == null) continue;

                        if (jsonObj.Contains(m_NameItem) && jsonObj.Contains(m_ValueItem))
                        {
                            string val = jsonObj[m_ValueItem].ToString();
                            if (val == var.CurrentValue)
                            {
                                if ((cbox.SelectedItem == null) || ((cbox.SelectedItem as ComboBoxItem).Tag.ToString() != val))
                                {
                                    cbox.SelectedItem = cbox.Items[i];
                                }
                                break;
                            }
                        }
                    }
                }
                /*
                using (JsonParser parser = new JsonParser(new StringReader(var.Value), true))
                {
                    JsonArray array = parser.ParseArray();
                    for (int i = 0; i < array.Count; i++)
                    {
                        JsonObject obj = (JsonObject)array[i];
                        if (obj.ContainsKey(m_NameItem) && obj.ContainsKey(m_ValueItem))
                        {
                            string val = obj[m_ValueItem].ToString();
                            if (val == var.CurrentValue)
                            {
                                if ((cbox.SelectedItem == null) || ((cbox.SelectedItem as ComboBoxItem).Tag.ToString() != val))
                                {
                                    cbox.SelectedItem = cbox.Items[i];
                                }
                                break;
                            }
                        }
                    }
                }
                */
            }
        }

        private void cbox_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_Context != null)
            {
                IExecutionContext exe = (IExecutionContext)m_Context.Services.GetService(typeof(IExecutionContext));
                IUserTaskManager taskManager = (IUserTaskManager)m_Context.Services.GetService(typeof(IUserTaskManager));
                if (exe != null && taskManager != null)
                {
                    //TODO: Асинхронно
                    var item = (cbox.SelectedItem as ComboBoxItem).Tag.ToString();
                    taskManager.RunTaskAsync(String.Format(Localization.AppTask_ExecutingServiceCommand, "ModifyVariable"), state =>
                    {
                        exe.ModifyVariable(m_Context, m_Variable, item);
                    });
                }

            }
        }

        #region IEditableObject Members

        public void BeginEdit()
        {
        }

        public void CancelEdit()
        {
        }

        public void EndEdit()
        {
            var exec = (IExecutionContext)m_Context.Services.GetService(typeof(IExecutionContext));
            var taskManager = (IUserTaskManager)m_Context.Services.GetService(typeof(IUserTaskManager));
            if (exec != null && taskManager != null && this.ADataSource == null)
            {
                //taskManager.RunTaskAsync(String.Format(Localization.AppTask_ExecutingServiceCommand, "GetVariable"), state =>
                //{
                BrickVariable var = exec.GetVariable(m_Context, m_Variable);
                    taskManager.Dispatcher.BeginInvoke(() =>
                    {
                        if (this.m_FirstLoad)
                        {
                            this.PopulateItems(var);
                            this.IsEnabled = true;
                        }
                        this.m_FirstLoad = false;
                        this.SetDefaultValue(var);
                    });
                    //});
            }

            if (!this.IsEnabled)
                this.IsEnabled = true;
            this.PopulateItems(this.m_DataSource);
        }
        #endregion

        private void PopulateItems(object dataSource)
        {
            if (dataSource == null)
            {
                return;
            }

            cbox.Items.Clear();
            if (dataSource is CellSetData)
            {
                var data = this.ADataSource as CellSetData;
                int i = 0;
                foreach (var rows in data.Axes[0].Positions)
                {
                    int j = 0;
                    FlatDescriptionCollection source = new FlatDescriptionCollection();
                    foreach (var columns in data.Axes[1].Positions)
                    {

                        FlatDescription obj = new FlatDescription();
                        if (!String.IsNullOrEmpty(data.Axes[0].Members[columns.Members[0].Id].Caption))
                        {
                            //obj.Argument = columns.Members[0].Caption;
                            obj.ArgumentSegments.Add(data.Axes[0].Members[columns.Members[0].Id].Caption);
                            var value = data.GetCellDescription(i, j).Value.Value;
                            obj.DisplayValue = value;
                            source.Add(obj);
                            SelectorItem item = new SelectorItem();
                            item.Content = obj.Argument;
                            item.Tag = obj.DisplayValue;
                            cbox.Items.Add(item);
                        }
                        j++;
                    }
                    i++;
                }

                cbox.SelectedIndex = 0;
                //dataSource = (dataSource as CellSetData).FlatData;
            }

            if (dataSource is DataTableWrapper)
            {
                var data = dataSource as DataTableWrapper;
                RelationalData[] bindCollection = new RelationalData[data.RowCount];
                int i = 0;
                int j = 0;
                for (j = 0; j < data.RowCount; j++)
                {
                    var bindObject =
                    new RelationalData() { First = data.Items[i], Second = Convert.ToInt32(data.Items[i + 1]) };
                    i += 2;
                    bindCollection[j] = bindObject;
                    SelectorItem item = new SelectorItem();
                    item.Content = bindObject.First;
                    item.Tag = bindObject.Second.ToString();
                    cbox.Items.Add(item);
                }
                cbox.SelectedIndex = 0;
                //foreach (DataTableColumnDefinition row in (dataSource as DataTableWrapper).Columns)
                //{

                //    PropertyDescriptor descriptorValue = TypeDescriptor.GetProperties(row)[m_ValueItem];
                //    PropertyDescriptor descriptorName = TypeDescriptor.GetProperties(row)[m_NameItem];
                //    if ((descriptorValue != null) && ((descriptorName != null)))
                //    {
                //        ComboBoxItem item = new ComboBoxItem(
                //            descriptorName.GetValue(row).ToString(),
                //            descriptorValue.GetValue(row).ToString());
                //        cbox.Items.Add(item);
                //    }
                //}
            }

            //cbox.SelectedIndex = 0;
        }
    }

    public class SelectorItem : ComboBoxItem
    {
        public SelectorItem()
        {
            base.DefaultStyleKey = typeof(SelectorItem);
        }
    }
}